package br.org.isvi.interpretador.portugol.operations;

import br.org.isvi.interpretador.portugol.InterpreterResolver;
import br.org.isvi.interpretador.portugol.OperationResolver;
import br.org.isvi.interpretador.portugol.types.IntegerSymbol;
import br.org.isvi.interpretador.portugol.types.Kind;
import br.org.isvi.interpretador.portugol.types.NumberSymbol;
import br.org.isvi.interpretador.portugol.types.RealSymbol;
import br.org.isvi.interpretador.portugol.types.StringSymbol;
import br.org.isvi.interpretador.portugol.types.Symbol;
import br.org.isvi.interpretador.portugol.types.Variable;
import br.org.isvi.interpretador.portugol.types.VariableType;

/**
 * Espera dois termos para somar
 * 
 * @author abraaoisvioliveirasouzadocarmo
 * 
 */
public class SumResolver implements OperationResolver {

	private double resultado = 0;
	private Kind kindResult = Kind.INTEIRO;

	public Symbol execute() {
		Symbol obj1, obj2 = null;
		Symbol ret = null;

		obj1 = InterpreterResolver.instance.popStack();
		obj2 = InterpreterResolver.instance.popStack();

		//CONCATENAÇÃO DE STRINGS
		if (UtilsValidator.getRealVariableValue(obj2).getKind() == Kind.TEXTO) {

			StringBuffer bf = new StringBuffer().append(UtilsValidator.getRealVariableValue(obj2).toString());
			bf.append(obj1.toString());

			kindResult = Kind.TEXTO;
			ret = new StringSymbol(bf.toString());
			
		} else {

			UtilsValidator.verifyKind(obj1, obj2);

			execute(obj1);
			execute(obj2);

			switch (kindResult) {
			case REAL:
				ret = new RealSymbol(resultado);
				break;
			case INTEIRO:
				ret = new IntegerSymbol((int) resultado);
				break;
			}

			kindResult = Kind.INTEIRO;
			resultado = 0;
		}

		return ret;
	}

	private void execute(Symbol obj) {
		if (obj instanceof Variable) {
			Variable o = (Variable) obj;
			o = InterpreterResolver.instance.getVariable(o.getName());

			if (o.getType() == VariableType.real)
				kindResult = Kind.REAL;

			if (o.getValue() instanceof IntegerSymbol) {
				IntegerSymbol valor = (IntegerSymbol) o.getValue();
				sum(((Number) valor.getValue()).doubleValue());

			} else if (o.getValue() instanceof RealSymbol) {
				RealSymbol valor = (RealSymbol) o.getValue();
				sum(((Number) valor.getValue()).doubleValue());
			}
		} else if (obj instanceof RealSymbol) {
			kindResult = Kind.REAL;
			sum(((Number) ((RealSymbol) obj).getValue()).doubleValue());
		} else if (obj instanceof IntegerSymbol) {
			sum(((Number) ((IntegerSymbol) obj).getValue()).doubleValue());
		}
	}

	private void sum(double val) {
		resultado = resultado + val;
	}

	public Symbol castToVarTypeIfPossible(Symbol value, Variable var) {
		Symbol ret = value;

		if (value instanceof NumberSymbol) {
			if (var.getType() == VariableType.inteiro) {

				ret = new IntegerSymbol(((Number) value.getValue()).intValue());

			} else if (var.getType() == VariableType.real) {

				ret = new RealSymbol(((Number) value.getValue()).doubleValue());

			}
		}

		return ret;
	}

}
